const {
	pinyinUtils,
	pinyinMultiple,
	pinyinIdentify,
	identifyToContent
} = require('@/pages/voice/utils/request/pinyin-utils')
/**
 * 文本转SSML语法
 * @param {Object} text	文本
 * @param {Object} type	类型		（默认）wx 微信
 */
const textToSsml = function(text, type = "wx") {

	switch (type) {
		case "wx":
			text = handlePause(text)
			text = handlePinyin(text)
			text = wxTextToSsml(text);
			break;
		default:
			text = handlePause(text)
			text = handlePinyin(text)
			text = wxTextToSsml(text);
	}

	return text;
}

/**
 * 处理停顿
 * @param {Object} text		需处理的文本内容
 * @param {Object} type		处理方式
 */
const handlePause = function(text, type = "wx", remove = false) {
	let res = text
	if (type === "wx") {
		const reg = /\[停顿:\w{2,6}\]/ig;
		const resp = text.match(reg)
		if (resp) {
			let matchSet = []
			for (let respStr of resp) {
				if (!(matchSet.indexOf(respStr) >= 0)) {
					matchSet.push(respStr)
				}
			}
			for (let setVal of matchSet) {
				if (remove) {
					res = res.replaceAll(setVal, "")
				} else {
					const newVal = setVal.replace("[停顿:", "<break time=\"").replace("]", "\"/>");
					res = res.replaceAll(setVal, newVal)
				}
			}
		}
	}
	return res
}

/**
 * @param {Object} text		需处理的文本内容
 * @param {Object} type		处理方式 （默认）wx 微信
 */
const handlePinyin = function(text, type = "wx") {
	let res = text
	if (type === "wx") {
		const reg = /\[读音:\S{1,8}\]/ig;
		const resp = text.match(reg)
		if (resp) {
			let matchSet = []
			for (let respStr of resp) {
				if (!(matchSet.indexOf(respStr) >= 0)) {
					matchSet.push(respStr)
				}
			}
			for (let setVal of matchSet) {
				const index = setVal.indexOf(setVal.match(/[0-9]/));
				let newVal = setVal.substring(0, (index + 1)) + "\">" + setVal.substring((index + 1), setVal.length)
				newVal = newVal.replace("[读音:", "<phoneme alphabet=\"py\" ph=\"").replace("]", "</phoneme>");
				res = res.replaceAll(setVal, newVal)
			}
		}
	}
	return res
}

/**
 * 微信文本转SSML语法
 * @param {Object} text	文本
 */
function wxTextToSsml(text) {
	let ssml = "<speak>";
	ssml = ssml.concat(text);
	ssml = ssml.concat("</speak>");
	return ssml;
}

/**
 * 断句
 * @param {Object} text	text文本内容
 */
const chunkingText = function(text) {
	let res = []

	// 正则校验
	const duyinSingleReg = /\[读音:\S{1,8}\]/;
	const tdSingleReg = /\[停顿:\S{1,8}\]/;
	// 断句正则
	var dj2Reg = /[\.|\?|\!|\。|\？|\！|\n]+["|”][\n]*/;
	var djReg = /[\.|\?|\!|\。|\？|\！|\n]+[\n]*/;
	// 断句标识
	const chunkingMarkArr = [".", "!", "?", "。", "！", "？", "\n"]

	// 断句长度句柄
	const markNum = 140

	// 显示文本句柄
	let textStr = "";
	// 真实文本句柄
	let realTextStr = "";
	// 循环读取文本
	for (let i = 0; i < text.length; i++) {
		let textVal = text[i]
		let dataText = textVal
		// 判断是否是[
		if (dataText === "[") {
			// 获取剩余字段
			const residueText = text.substring(i, text.length)
			// 正则匹配
			let resp = residueText.match(duyinSingleReg)
			// 判断是否批次成功且第一个就是标注读音的多音字
			if (resp !== null && resp.index === 0) {
				// 获取匹配结果
				const regRespText = resp[0]
				// 获取标注后的多音字
				textVal = regRespText
				// 获取多音字
				dataText = regRespText.slice(-2, -1)
				// 跳过剩余字段
				i += (regRespText.length - 1)
				// 设置显示文本及真实文本
				textStr += textVal
				realTextStr += dataText
			} else {
				resp = residueText.match(tdSingleReg)
				if (resp !== null && resp.index === 0) {
					// 获取匹配结果
					const regRespText = resp[0]
					// 获取停顿
					textVal = regRespText
					// 跳过剩余字段
					i += (regRespText.length - 1)
					// 设置显示文本 且 不设置真实文本
					textStr += textVal
				}
			}

		} else if (chunkingMarkArr.includes(textVal)) {
			// 获取剩余字段
			const residueText = text.substring(i, text.length)
			// 判断是否说话内容
			let resp = residueText.match(dj2Reg)
			if (resp && resp.index === 0) {
				// 获取匹配结果
				const regRespText = resp[0]
				// 跳过剩余字段
				i += (regRespText.length - 1)
				// 设置显示文本及真实文本
				textStr += regRespText;
				// 真实文本句柄
				realTextStr += regRespText;

				// 判断真实长度是否大于140
				if (realTextStr.length === markNum) {
					// 设置断句
					res.push({
						text: textStr.substring(0, markNum),
						realText: realTextStr.substring(0, markNum)
					})
					// 设置显示文本及真实文本 置空
					textStr = textStr.substring(markNum, textStr.length),
						realTextStr = realTextStr.substring(markNum, realTextStr.length)
				} else {
					// 设置断句
					res.push({
						text: textStr,
						realText: realTextStr
					})
					// 设置显示文本及真实文本 置空
					textStr = ""
					realTextStr = ""
				}

			} else {
				resp = residueText.match(djReg)
				if (resp && resp.index === 0) {
					// 获取匹配结果
					const regRespText = resp[0]
					// 跳过剩余字段
					i += (regRespText.length - 1)
					// 设置显示文本及真实文本
					textStr += regRespText;
					// 真实文本句柄
					realTextStr += regRespText;
					// 判断真实长度是否大于140
					if (realTextStr.length === markNum) {
						// 设置断句
						res.push({
							text: textStr.substring(0, markNum),
							realText: realTextStr.substring(0, markNum)
						})
						// 设置显示文本及真实文本 置空
						textStr = textStr.substring(markNum, textStr.length),
							realTextStr = realTextStr.substring(markNum, realTextStr.length)
					} else {
						// 设置断句
						res.push({
							text: textStr,
							realText: realTextStr
						})
						// 设置显示文本及真实文本 置空
						textStr = ""
						realTextStr = ""
					}
				}
			}
		} else {
			// 判断真实长度是否大于140 断句
			if (realTextStr.length === markNum) {
				// 设置断句
				res.push({
					// 显示文本
					text: textStr,
					// 真实文本
					realText: realTextStr
				})
				// 设置显示文本及真实文本 置空
				textStr = textVal
				realTextStr = textVal
			} else {
				// 设置显示文本及真实文本
				textStr += textVal;
				// 真实文本句柄
				realTextStr += textVal;
			}

		}
	}

	if (textStr !== "") {
		// 设置断句
		res.push({
			// 显示文本
			text: textStr,
			// 真实文本
			realText: realTextStr
		})
		// 设置显示文本及真实文本 置空
		textStr = ""
		realTextStr = ""
	}

	return res
}

/**
 * 长文本拆分
 * @param {Object} text		text文本内容
 * @param {Object} type		type类型 (默认 wx 微信)
 */
const longTextSplit = function(text, type = "wx") {
	let res = []

	// 正则校验
	const duyinSingleReg = /\[读音:\S{1,8}\]/;
	const tdSingleReg = /\[停顿:\S{1,8}\]/;
	// 断句正则
	var dj2Reg = /[\.|\?|\!|\。|\？|\！|\n]+["|”][\n]*/;
	var djReg = /[\.|\?|\!|\。|\？|\！|\n]+[\n]*/;
	// 断句标识
	const chunkingMarkArr = [".", "!", "?", "。", "！", "？", "\n"]

	// 断句长度句柄
	const markNum = 140

	// 显示文本句柄
	let textStr = "";
	// 真实文本句柄
	let realTextStr = "";
	// 循环读取文本
	for (let i = 0; i < text.length; i++) {
		let textVal = text[i]
		let dataText = textVal
		// 判断是否是[
		if (dataText === "[") {
			// 获取剩余字段
			const residueText = text.substring(i, text.length)
			// 正则匹配
			let resp = residueText.match(duyinSingleReg)
			// 判断是否批次成功且第一个就是标注读音的多音字
			if (resp !== null && resp.index === 0) {
				// 获取匹配结果
				const regRespText = resp[0]
				// 获取标注后的多音字
				textVal = regRespText
				// 获取多音字
				dataText = regRespText.slice(-2, -1)
				// 跳过剩余字段
				i += (regRespText.length - 1)
				// 设置显示文本及真实文本
				textStr += textVal
				realTextStr += dataText
			} else {
				resp = residueText.match(tdSingleReg)
				if (resp !== null && resp.index === 0) {
					// 获取匹配结果
					const regRespText = resp[0]
					// 获取停顿
					textVal = regRespText
					// 跳过剩余字段
					i += (regRespText.length - 1)
					// 设置显示文本 且 不设置真实文本
					textStr += textVal
				}
			}

		} else if (chunkingMarkArr.includes(textVal)) {
			// 获取剩余字段
			const residueText = text.substring(i, text.length)
			// 判断是否说话内容
			let resp = residueText.match(dj2Reg)
			if (resp && resp.index === 0) {
				// 获取匹配结果
				const regRespText = resp[0]
				// 跳过剩余字段
				i += (regRespText.length - 1)
				// 设置显示文本及真实文本
				textStr += regRespText;
				// 真实文本句柄
				realTextStr += regRespText;

				// 判断真实长度是否大于140
				if (realTextStr.length === markNum) {
					// 设置断句
					res.push({
						text: textStr.substring(0, markNum),
						realText: realTextStr.substring(0, markNum)
					})
					// 设置显示文本及真实文本 置空
					textStr = textStr.substring(markNum, textStr.length),
						realTextStr = realTextStr.substring(markNum, realTextStr.length)
				} else {
					// 设置断句
					res.push({
						text: textStr,
						realText: realTextStr
					})
					// 设置显示文本及真实文本 置空
					textStr = ""
					realTextStr = ""
				}

			} else {
				resp = residueText.match(djReg)
				if (resp && resp.index === 0) {
					// 获取匹配结果
					const regRespText = resp[0]
					// 跳过剩余字段
					i += (regRespText.length - 1)
					// 设置显示文本及真实文本
					textStr += regRespText;
					// 真实文本句柄
					realTextStr += regRespText;
					// 判断真实长度是否大于140
					if (realTextStr.length === markNum) {
						// 设置断句
						res.push({
							text: textStr.substring(0, markNum),
							realText: realTextStr.substring(0, markNum)
						})
						// 设置显示文本及真实文本 置空
						textStr = textStr.substring(markNum, textStr.length),
							realTextStr = realTextStr.substring(markNum, realTextStr.length)
					} else {
						// 设置断句
						res.push({
							text: textStr,
							realText: realTextStr
						})
						// 设置显示文本及真实文本 置空
						textStr = ""
						realTextStr = ""
					}
				}
			}
		} else {
			// 判断真实长度是否大于140 断句
			if (realTextStr.length === markNum) {
				// 设置断句
				res.push({
					// 显示文本
					text: textStr,
					// 真实文本
					realText: realTextStr
				})
				// 设置显示文本及真实文本 置空
				textStr = textVal
				realTextStr = textVal
			} else {
				// 设置显示文本及真实文本
				textStr += textVal;
				// 真实文本句柄
				realTextStr += textVal;
			}

		}
	}

	if (textStr !== "") {
		// 设置断句
		res.push({
			// 显示文本
			text: textStr,
			// 真实文本
			realText: realTextStr
		})
		// 设置显示文本及真实文本 置空
		textStr = ""
		realTextStr = ""
	}

	// 返回响应合成数据
	let resSplitText = []
	realTextStr = ""
	textStr = ""
	// console.log("res",res)
	const resLen = res.length
	for (let i = 0; i < res.length; i++) {
		const resTextObj = res[i]
		if (resTextObj) {
			textStr += resTextObj.text
			realTextStr += resTextObj.realText
			// 校验下一文本是否超长
			let nextTextStr = "";
			if(i < (resLen - 1)){
				nextTextStr = realTextStr + res[i + 1].realText
			}
			else if (i === (resLen - 1)) {
				nextTextStr = realTextStr
				textStr = textStr + "[停顿:1s]"
			}
			else {
				nextTextStr = realTextStr
			}
			// console.log("textStr",textStr)
			// console.log("nextTextStr",nextTextStr.length,nextTextStr)
			if (nextTextStr.length <= 145) {
				continue
			}
			// 合成文本处理
			let longText = "";
			if (type === "wx") {
				longText = textToSsml(textStr, "wx")
			}

			if (longText !== "") {
				realTextStr = ""
				textStr = ""
				resSplitText.push(longText)
			}
		}

	}

	// 处理最后一次循环数据
	if (textStr !== "") {
		// 合成文本处理
		let longText = "";
		if (type === "wx") {
			longText = textToSsml(textStr, "wx")
		}

		if (longText !== "") {
			realTextStr = ""
			textStr = ""
			resSplitText.push(longText)
		}
	}

	return resSplitText
}

/**
 * 获取真实文本
 * @param {Object} text
 */
const getRealTextByText = function(text) {
	// 正则校验
	const duyinSingleReg = /\[读音:\S{1,8}\]/;
	const tdSingleReg = /\[停顿:\S{1,8}\]/;

	// 真实文本句柄
	let realTextStr = "";
	// 循环读取文本
	for (let i = 0; i < text.length; i++) {
		let textVal = text[i]
		let dataText = textVal
		// 判断是否是[
		if (dataText === "[") {
			// 获取剩余字段
			const residueText = text.substring(i, text.length)
			// 正则匹配
			let resp = residueText.match(duyinSingleReg)
			// 判断是否批次成功且第一个就是标注读音的多音字
			if (resp !== null && resp.index === 0) {
				// 获取匹配结果
				const regRespText = resp[0]
				// 获取多音字
				dataText = regRespText.slice(-2, -1)
				// 跳过剩余字段
				i += (regRespText.length - 1)
				// 设置真实文本
				realTextStr += dataText
			} else {
				resp = residueText.match(tdSingleReg)
				if (resp !== null && resp.index === 0) {
					// 获取匹配结果
					const regRespText = resp[0]
					// 跳过剩余字段
					i += (regRespText.length - 1)
				}
			}

		} else {
			// 设置真实文本
			realTextStr += textVal;
		}
	}

	return realTextStr;
}

/**
 * 语速转换
 * @param {Object} speed
 */
const realToSpeed = function(speed) {
	let arg = -1;
	if (speed > 2.5 || speed < 0.6) {
		return -1
	}

	if (0.6 <= speed && speed < 0.8) {
		arg = -2 + (speed - 0.6) / (0.8 - 0.6) * ((-1) - (-2))
	} else if (0.8 <= speed && speed < 1.0) {
		arg = -1 + (speed - 0.8) / (1.0 - 0.8) * (0 - (-1))
	} else if (1.0 <= speed && speed < 1.2) {
		arg = 0 + (speed - 1.0) / (1.2 - 1.0) * (1 - 0)
	} else if (1.2 <= speed && speed < 1.5) {
		arg = 1 + (speed - 1.2) / (1.5 - 1.2) * (2 - 1)
	} else if (1.5 <= speed && speed <= 2.5) {
		arg = 2 + (speed - 1.5) / (2.5 - 1.5) * (6 - 2)
	}
	arg = Math.round(arg, 2)
	if (arg === -0) {
		arg = 0
	}
	return arg
}

/**
 * 时间转换
 * @param {Object} millisecond
 */
const formatTime = function(millisecond) {
	let seconds = Math.floor(millisecond / 1000);
	let result = [];
	let count = 2;
	while (count >= 0) {
		let current = Math.floor(seconds / (60 ** count));
		result.push(current);
		seconds -= current * (60 ** count);
		--count;
	}
	return result.map(item => item <= 9 ? `0${item}` : item).join(":")
}

/**
 * 时间转换精确到毫秒
 * @param {Object} millisecond
 */
const formatTimeToMillisecond = function(millisecond) {
	let seconds = Math.floor(millisecond / 1000);
	let result = [];
	let count = 2;
	while (count >= 0) {
		let current = Math.floor(seconds / (60 ** count));
		result.push(current);
		seconds -= current * (60 ** count);
		--count;
	}
	const lastNum = millisecond % 1000;
	return result.map(item => item <= 9 ? `0${item}` : item).join(":") + "," + handleLastNum(lastNum)
}

/**
 * 处理毫秒时间
 * @param {Object} lastNum
 */
const handleLastNum = function(lastNum) {
	if (lastNum < 10) {
		return "00" + lastNum
	} else if (lastNum < 100) {
		return "0" + lastNum
	} else {
		return lastNum
	}
}

/**
 * 获取生成lrc文件内容
 * @param {Object} subtitles
 */
const getAudioTextLrcMap = function(subtitles) {
	let outPutMap = null;
	const chunkingMarkArr = [".", "!", "?", "。", "！", "？", ",", "，"];
	const continueMarkArr = ["\"", "'", "‘", "’"];
	if (subtitles && subtitles.length > 0) {
		let textStr = "";
		outPutMap = [];
		let outPutObj = null;
		let itemObj = null;
		let count = 0
		let nextCount = 1
		let timeStr = ""
		for (let item of subtitles) {
			itemObj = item;
			if (count !== nextCount) {
				timeStr = formatTime(itemObj.EndTime)
				count++
			}
			if (continueMarkArr.includes(itemObj.Text)) {
				continue
			} else if (chunkingMarkArr.includes(itemObj.Text)) {
				if (textStr === "") {
					continue
				}
				outPutObj = {
					time: timeStr,
					text: textStr
				}
				outPutMap.push(outPutObj)
				textStr = "";
				timeStr = "";
				nextCount++
				continue
			}
			textStr += itemObj.Text;

		}
		if (textStr !== "") {
			outPutObj = {
				time: timeStr,
				text: textStr
			}
			outPutMap.push(outPutObj)
			textStr = "";
			timeStr = "";
		}
	}

	return outPutMap;
}

/**
 * 获取生成srt文件内容
 * @param {Object} subtitles
 */
const getAudioTextSrtMap = function(subtitles){
	let outPutMap = null;
	const chunkingMarkArr = [".","!","?","。","！","？",",","，"];
	const continueMarkArr = ["\"","'","‘","’"];
	if (subtitles && subtitles.length > 0) {
		let textStr = "";
		outPutMap = [];
		let outPutObj = null;
		let itemObj = null;
		let firstObj = null;
		let lastObj =null;
		for(let item of subtitles){
			itemObj = item
			
			if(continueMarkArr.includes(itemObj.Text)){
				continue
			}
			else if (chunkingMarkArr.includes(itemObj.Text)) {
				// console.log("firstObj",firstObj)
				// console.log("lastObj",lastObj)
				outPutObj = {
					starttime: formatTimeToMillisecond(firstObj.BeginTime),
					endtime:formatTimeToMillisecond(lastObj.EndTime),
					text:textStr
				}
				outPutMap.push(outPutObj)
				// 清除拼接字符
				textStr = ""
				// 清除第一个字符
				firstObj = null
				continue
			}
			// 判断第一个字符是否为空，是则设置
			if(firstObj == null){
				firstObj = item
			}
			// 设置最后一个字符
			lastObj = item
			textStr += itemObj.Text;
			
		}
		// 处理最后一次循环
		if(textStr !== ""){
			outPutObj = {
				starttime: formatTimeToMillisecond(firstObj.BeginTime),
				endtime:formatTimeToMillisecond(lastObj.EndTime),
				text:textStr
			}
			outPutMap.push(outPutObj)
			// 清除拼接字符
			textStr = ""
			// 清除第一个字符
			firstObj = null
		}
		// console.log(outPutMap)
	}
	
	return outPutMap;
}

module.exports = {
	/**
	 * 文本转SSML语法
	 * @param {Object} text	文本
	 * @param {Object} type	类型		（默认）wx 微信
	 */
	textToSsml,
	/**
	 * 处理停顿
	 * @param {Object} text		需处理的文本内容
	 * @param {Object} type		处理方式（默认）wx 微信
	 * @param {Object} remove  是否移除表示（默认）false
	 */
	handlePause,
	/**
	 * @param {Object} text		需处理的文本内容
	 * @param {Object} type		处理方式 （默认）wx 微信
	 */
	handlePinyin,
	/**
	 * 拼音转换工具
	 * @tutorial https://pinyin-pro.cn/
	 * @param {String} text  (必传)：string 类型，需要进行拼音转换的字符串
	 * @param {Object} options   (可选)：object 类型，转换输出的内容及格式，详细见https://pinyin-pro.cn/
	 * 
	 * @returns
	 */
	pinyinUtils,
	/**
	 * 多音字
	 * @tutorial https://pinyin-pro.cn/
	 * @param {String} text  (必传)：string 类型，需要进行拼音转换的字符串
	 * @param {Object} options
	 * @param {Object} options.type	输出结果的类型
	 * 
	 * @returns
	 */
	pinyinMultiple,
	/**
	 * 多音字识别
	 * @tutorial https://pinyin-pro.cn/
	 * @param {String} text  (必传)：string 类型，需要进行拼音转换的字符串
	 * 
	 * @returns array
	 */
	pinyinIdentify,
	/**
	 * 多音字配置转内容
	 * @param {Object} identifyArr
	 */
	identifyToContent,
	/**
	 * 断句
	 * @param {Object} text	
	 */
	chunkingText,
	/**
	 * 长文本拆分
	 * @param {Object} text		text文本内容
	 * @param {Object} type		type类型 (默认 wx 微信)
	 */
	longTextSplit,
	/**
	 * 获取真实文本
	 * @param {Object} text
	 */
	getRealTextByText,
	/**
	 * 语速转换
	 * @param {Object} speed
	 */
	realToSpeed,
	/**
	 * 获取生成lrc文件内容
	 * @param {Object} subtitles
	 */
	getAudioTextLrcMap,
	/**
	 * 获取生成srt文件内容
	 * @param {Object} subtitles
	 */
	getAudioTextSrtMap
}